{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "qFdPvlXBOdUN"
      },
      "source": [
        "# 난수 생성"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/random_numbers\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />TensorFlow.org에서 보기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/guide/random_numbers.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />구글 코랩(Colab)에서 실행하기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/guide/random_numbers.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />깃허브(GitHub)에서 소스 보기</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/guide/random_numbers.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />노트북 다운로드하기</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "P01gSITDsuKa"
      },
      "source": [
        "Note: 이 문서는 텐서플로 커뮤니티에서 번역했습니다. 커뮤니티 번역 활동의 특성상 정확한 번역과 최신 내용을 반영하기 위해 노력함에도\n",
        "불구하고 [공식 영문 문서](https://www.tensorflow.org/?hl=en)의 내용과 일치하지 않을 수 있습니다.\n",
        "이 번역에 개선할 부분이 있다면\n",
        "[tensorflow/docs-l10n](https://github.com/tensorflow/docs-l10n/) 깃헙 저장소로 풀 리퀘스트를 보내주시기 바랍니다.\n",
        "문서 번역이나 리뷰에 참여하려면\n",
        "[docs-ko@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ko)로\n",
        "메일을 보내주시기 바랍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "BlGY1iiph_C2"
      },
      "source": [
        "텐서플로는 `tf.random` 모듈에서 유사 난수 생성기(pseudo random number generator, RNG)를 제공 합니다. 이 문서에서는 난수 생성기를 다루는 방법과 이 기능이 어떻게 다른 텐서플로의 서브 시스템과 상호작용 하는지 설명합니다. \n",
        "\n",
        "텐서플로는 난수 생성 프로세스를 다루기 위한 두 가지 방식을 제공합니다:\n",
        "\n",
        "1. `tf.random.Generator` 객체 사용을 통한 방식. 각 객체는 상태를 (`tf.Variable` 안에) 유지합니다. 이 상태는 매 숫자 생성때마다 변하게 됩니다.\n",
        "\n",
        "2. `tf.random.stateless_uniform`와 같은 순수-함수형으로 상태가 없는 랜덤 함수를 통한 방식. 같은 디바이스에서 동일한 인수를 (시드값 포함) 통해 해당 함수를 호출 하면 항상 같은 결과를 출력 합니다.\n",
        "\n",
        "주의: `tf.random.uniform` 와 `tf.random.normal` 같은 구버전 TF 1.x의 RNG들은 아직 삭제되지 않았지만 사용을 권장하지 않습니다.\n",
        "\n",
        "주의: 랜덤 함수는 텐서 플로 버전에 따라 동일함을 보장하지 않습니다. 참조: [버전 호환성](https://www.tensorflow.org/guide/versions#what_is_not_covered)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "zIGh9faCOp6x"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "ECDrttf0s8Nu"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "\n",
        "# 분산 전략을 위해 2개의 가상 디바이스 cpu:0 and cpu:1 를 생성 합니다.\n",
        "physical_devices = tf.config.experimental.list_physical_devices(\"CPU\")\n",
        "tf.config.experimental.set_virtual_device_configuration(\n",
        "    physical_devices[0], [\n",
        "        tf.config.experimental.VirtualDeviceConfiguration(),\n",
        "        tf.config.experimental.VirtualDeviceConfiguration()\n",
        "    ])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "eqMlrUsVu2Ai"
      },
      "source": [
        "## `tf.random.Generator` 클래스\n",
        "\n",
        "각 RNG 호출마다 다른 결과를 생성하기 원할 경우 `tf.random.Generator` 클래스를 사용할 수 있습니다. 이는 내부 상태를 (`tf.Variable` 객체가 관리) 유지 합니다. 이 상태는 난수가 생성될때마다 업데이트 됩니다. 상태가 `tf.Variable`에 의해 유지되기 때문에, 쉬운 체크포인팅(checkpointing), 자동적인 컨트롤 종속, 쓰레드(thread) 안전성의 장점이 있습니다.\n",
        "\n",
        "클래스를 통해서 객체를 직접 생성하거나 전역 생성기를 반환하는 `tf.random.get_global_generator()` 를 호출하여 `tf.random.Generator` 를 사용할 수 있습니다. :"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "7yU1E3JvxOQD"
      },
      "outputs": [],
      "source": [
        "g1 = tf.random.Generator.from_seed(1)\n",
        "print(g1.normal(shape=[2, 3]))\n",
        "g2 = tf.random.get_global_generator()\n",
        "print(g2.normal(shape=[2, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "QmRCeAvTxulW"
      },
      "source": [
        "객체를 생성하는데에는 여러 방법이 있습니다. 위에서 볼 수 있는것 처럼 가장 쉬운 방법은 `Generator.from_seed`를 사용하는 것이며 이는 시드로부터 생성기를 생성 합니다. 시드는 0 이상의 정수입니다. `from_seed`는 `alg`를 추가적으로 전달 받을 수 있으며 이는 생성기가 사용할 RNG 알고리즘 입니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "kISbOE4Xfjhv"
      },
      "outputs": [],
      "source": [
        "g1 = tf.random.Generator.from_seed(1, alg='philox')\n",
        "print(g1.normal(shape=[2, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "_mCRaN7dfd8j"
      },
      "source": [
        "추가적인 정보는 아래 *알고리즘* 섹션을 참고해 주세요.\n",
        "\n",
        "생성기를 생성하는 다른 방법은 `Generator.from_non_deterministic_state`를 사용하는 것 입니다. 이 방법을 통해서 생성된 생성기는 비결정 상태에서 시작 합니다. 이 상태는 시간과 운영 체제 등에 영향을 받습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "gxPLCLsz00qY"
      },
      "outputs": [],
      "source": [
        "g = tf.random.Generator.from_non_deterministic_state()\n",
        "print(g.normal(shape=[2, 3]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "zSAp2BMj1JZ6"
      },
      "source": [
        "명백한 상태(explicit state)에서 생성기를 생성하는 방법 등 생성기를 초기화하는 방법은 여러가지가 있지만 해당 가이드에서는 다루지 않습니다.\n",
        "\n",
        "전역 생성기를 사용하기 위해서 `tf.random.get_global_generator`를 사용할 경우, 디바이스 환경에 유의해야 합니다. 전역 생성기는 `tf.random.get_global_generator`가 처음 호출될때 (비결정 상태로) 생성되고 기본 디바이스에 배치됩니다. 예를 들어서 `tf.random.get_global_generator`를 `tf.device(\"gpu\")` 영역에서 처음으로 호출하였을 경우, 전역 생성기는 GPU에 할당 되며, 추후에 CPU에서 사용할시에 GPU-CPU간 복제를 하게 됩니다.\n",
        "\n",
        "생성기를 다른 객체로 변경하기 위한 `tf.random.set_global_generator` 함수도 있습니다. 이 함수는 조심히 사용해야합니다. `tf.function`가 이전의 생성기를 (약한 참조로) 사용하고 있을 수 있으며, 이를 변경하는 것은 가비지 콜렉션(garbage collection)을 발생시켜 `tf.function`에 문제를 유발할 수 있습니다. 전역 생성기를 재설정 하는데에 더 좋은 방법은 `Generator.reset_from_seed` 와 같이 새로운 생성기를 생성하지 않는 \"리셋\" 함수를 사용하는 것 입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "324S5bpd9HRg"
      },
      "outputs": [],
      "source": [
        "g = tf.random.Generator.from_seed(1)\n",
        "print(g.normal([]))\n",
        "print(g.normal([]))\n",
        "g.reset_from_seed(1)\n",
        "print(g.normal([]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "z9H0wuvp9VwH"
      },
      "source": [
        "### 독립적인 난수 스트림 생성\n",
        "\n",
        "많은 어플리케이션에서는 서로 겹치지 않으며 통계적으로 상관관계를 가지지 않는 여러개의 독립적인 난수 스트림이 필요 합니다. 이는 각각 독립이 보장된 여러 생성기를 생성 하는 `Generator.split`를 통해서 해결 할 수 있습니다 (즉 독립 스트림 생성할 수 있습니다)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "Vg5_KN18OZjo"
      },
      "outputs": [],
      "source": [
        "g = tf.random.Generator.from_seed(1)\n",
        "print(g.normal([]))\n",
        "new_gs = g.split(3)\n",
        "for new_g in new_gs:\n",
        "  print(new_g.normal([]))\n",
        "print(g.normal([]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "dqOaGVzKOsRJ"
      },
      "source": [
        "`split`은 RNG의 `normal`과 같이 생성기의 (위의 예제에서는 `g`) 상태를 변경 합니다. 서로 독립인것과 더불어 새로운 생성기는 (`new_gs`) 또한 이전 생성기와 독립임을 보장 합니다 (`g`).\n",
        "\n",
        "새로운 생성기를 생성 하는 것은 디바이스간 복제의 오버헤드를 피하기 위해 사용하고 있는 생성기가 서로 다른 연산에서 동일한 디바이스에 있음을 확실히 하고 싶을때 유용합니다. 예를 들어: "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "5jSnJBlUQzF3"
      },
      "outputs": [],
      "source": [
        "with tf.device(\"cpu\"):  # \"cpu\"를 사용하고 싶은 디바이스로 변경\n",
        "  g = tf.random.get_global_generator().split(1)[0]  \n",
        "  print(g.normal([]))  # 전역 생성기와는 다르게 g를 사용하는 것은 디바이스간 복제를 발생하지 않습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "sCxbccYMRdd4"
      },
      "source": [
        "참고: 이론적으로, `split` 대신에 `from_seed` 생성자(Constructor)를 사용할 수 있습니다. 그러나 이는 새로운 생성기가 전역 생성기에 독립임을 보장하지 않습니다. 또한 두 생성기의 시드가 동일하거나 랜덤 생성 스트림이 겹치는 시드를 생성하는 등의 위험이 있습니다.\n",
        "\n",
        "`split`을 분할(split)된 생성기를 통해서 호출하면 재귀적으로 분할할 수 있습니다. 재귀 깊이의 제한은 없지만, 오버플로우는 방지하도록 되어있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "8JUgnQM_O0lg"
      },
      "source": [
        "### `tf.function`와의 상호 작용\n",
        "\n",
        "`tf.random.Generator`는 `tf.function`와 사용될 경우 `tf.Variable`와 동일한 규칙이 적용 됩니다. 이는 3가지 측면을 가집니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "jnSjhY6WM-J8"
      },
      "source": [
        "#### `tf.function` 밖에서 생성기 생성하기 \n",
        "\n",
        "`tf.function` 는 밖에서 생성된 생성기를 사용 할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "a5EEy0E2UHMw"
      },
      "outputs": [],
      "source": [
        "g = tf.random.Generator.from_seed(1)\n",
        "@tf.function\n",
        "def foo():\n",
        "  return g.normal([])\n",
        "print(foo())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "L_8kC7kbO5uu"
      },
      "source": [
        "사용자는 함수를 호출할때 생성기 객체가 여전히 살아 있음을 확인해야 합니다 (가비지 콜렉션이 되지 않아야 합니다)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "PwIrBv_zUYwI"
      },
      "source": [
        "#### `tf.function` 안에서 생성기 생성하기\n",
        "\n",
        "`tf.function` 안에서 생성기를 생성하는 경우는 오직 함수의 첫번째 호출에서만 실행 됩니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "3JzpUvqJU4MW"
      },
      "outputs": [],
      "source": [
        "g = None\n",
        "@tf.function\n",
        "def foo():\n",
        "  global g\n",
        "  if g is None:\n",
        "    g = tf.random.Generator.from_seed(1)\n",
        "  return g.normal([])\n",
        "print(foo())\n",
        "print(foo())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "UaTVnOhHVM9a"
      },
      "source": [
        "#### 생성기를 `tf.function`의 파라미터로 보내기\n",
        "\n",
        "`tf.function`의 파라미터로 사용될 경우, 동일한 상태 크기를 가진 서로 다른 생성기 객체는 `tf.function`를 재추적(retracing) 하지 않습니다 (상태 크기는 RNG 알고리즘에 의해 결정됩니다). 반면, 다른 상태 크기를 가질 경우에는 동작 합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "DeR9kvt0V-ad"
      },
      "outputs": [],
      "source": [
        "num_traces = 0\n",
        "@tf.function\n",
        "def foo(g):\n",
        "  global num_traces\n",
        "  num_traces += 1\n",
        "  return g.normal([])\n",
        "foo(tf.random.Generator.from_seed(1))\n",
        "foo(tf.random.Generator.from_seed(2))\n",
        "print(num_traces)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "fxcS6IY8WZuh"
      },
      "source": [
        "### 분산 전략(distribution strategies)과의 상호 작용 \n",
        "\n",
        "`Generator`가 분산 전략과 상호작용 하는 방식은 3가지가 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "GyZv9QJkZfkQ"
      },
      "source": [
        "#### 분산 전략 밖에서 생성기 생성\n",
        "\n",
        "생성기가 전략 스코프(scope) 밖에서 생성될 경우, 생성기에 대한 모든 복제(replicas)의 접근이 직렬화(serialized)되고 따라서 복제들은 서로 다른 난수를 가지게 됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "HX_beT9SZWMp"
      },
      "outputs": [],
      "source": [
        "g = tf.random.Generator.from_seed(1)\n",
        "strat = tf.distribute.MirroredStrategy(devices=[\"cpu:0\", \"cpu:1\"])\n",
        "with strat.scope():\n",
        "  def f():\n",
        "    print(g.normal([]))\n",
        "  results = strat.run(f)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ydYQbUqLPAgH"
      },
      "source": [
        "이 사용법은 생성기의 디바이스가 복제에 따라 다르기 때문에 성능에 대한 이슈가 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Yal4LbBKbAeN"
      },
      "source": [
        "#### 분산 전략(distribution strategies)안에서 생성기 생성하기\n",
        "\n",
        "전략 영역(strategy scopes)안에서 생성기를 생성하는 것은 허용되지 않았습니다. 이는 생성기를 어떻게 복제하는지에 대한 모호함이 있기 때문입니다 (예를 들어 각 복제본이 동일한 난수를 갖도록 복제를 하거나 서로 다른 난수를 갖도록 `split` 복제를 하는지에 대한 모호함이 있습니다)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "T6McVq-gbK_d"
      },
      "outputs": [],
      "source": [
        "strat = tf.distribute.MirroredStrategy(devices=[\"cpu:0\", \"cpu:1\"])\n",
        "with strat.scope():\n",
        "  try:\n",
        "    tf.random.Generator.from_seed(1)\n",
        "  except ValueError as e:\n",
        "    print(\"ValueError:\", e)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "pqQfWkMWQnnI"
      },
      "source": [
        "`Strategy.run`가 파라미터 함수를 전략 영역 안에서 암묵적으로 실행함을 유의해야합니다:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "X6Ceqha3RKKo"
      },
      "outputs": [],
      "source": [
        "strat = tf.distribute.MirroredStrategy(devices=[\"cpu:0\", \"cpu:1\"])\n",
        "def f():\n",
        "  tf.random.Generator.from_seed(1)\n",
        "try:\n",
        "  strat.run(f)\n",
        "except ValueError as e:\n",
        "  print(\"ValueError:\", e)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "ODLS8njzbUEF"
      },
      "source": [
        "#### 생성기를 `Strategy.run`의 파라미터로 사용하기\n",
        "\n",
        "각 복제본이 각자의 생성기를 사용하길 원할 경우, `n`개의 생성기가 필요합니다 (각각 복제하거나 split). `n`은 복제의 갯수이며 , 이를 `Strategy.run`의 파라미터로 보냅니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YurAsX3nbROP"
      },
      "outputs": [],
      "source": [
        "strat = tf.distribute.MirroredStrategy(devices=[\"cpu:0\", \"cpu:1\"])\n",
        "gs = tf.random.get_global_generator().split(2)\n",
        "# to_args는 run함수를 위한 파라미터를 생성하는 API의 대안 입니다. \n",
        "# 이는 추후에 API로 지원할 경우 교체될 예정 입니다.\n",
        "def to_args(gs):  \n",
        "  with strat.scope():\n",
        "    def f():\n",
        "      return [gs[tf.distribute.get_replica_context().replica_id_in_sync_group]]\n",
        "    return strat.run(f)\n",
        "args = to_args(gs)\n",
        "def f(g):\n",
        "  print(g.normal([]))\n",
        "results = strat.run(f, args=args)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "73an1POpsi6V"
      },
      "source": [
        "## 상태가 없는 RNG\n",
        "\n",
        "상태가 없는 RNG의 사용법은 간단합니다. 순수 함수이기 때문에 부작용이 없습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "0-aOOA3gasn_"
      },
      "outputs": [],
      "source": [
        "print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))\n",
        "print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "2O_D-RAFNH2Q"
      },
      "source": [
        "상태가 없는 모든 RNG는 `seed` 파라미터를 필요로 합니다. 이 파라미터는 크기가 `[2]`인 정수형 텐서입니다. 연산의 결과는 이 시드값에 의해 결정 됩니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "4BvGkPnaOUPF"
      },
      "source": [
        "## 알고리즘"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "58-8kvR4pRwO"
      },
      "source": [
        "### 일반\n",
        "\n",
        "`tf.random.Generator` 클래스와 `stateless` 함수는 모든 디바이스에서 필록스(Philox) 알고리즘을 지원합니다 (`\"philox\"` 또는 `tf.random.Algorithm.PHILOX`로 명시할 수 있습니다).\n",
        "\n",
        "만약 같은 알고리즘을 쓰고 같은 상태에서 시작할 경우 서로 다른 디바이스는 같은 정수를 생성합니다. 또한 \"거의 같은\" 부동 소수점 수를 생성합니다. 각 디바이스의 부동 소수점 연산의 방식에 따라 약간의 오차가 발생 할 수 있습니다. (예: reduction order)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "WETA04F1OYPL"
      },
      "source": [
        "### XLA 디바이스\n",
        "\n",
        "XLA 기반 디바이스에서는 (TPU와 XLA가 활성화된 CPU/GPU) ThreeFry 알고리즘을 지원 합니다. (`\"threefry\"` 또는 `tf.random.Algorithm.THREEFRY`) 이 알고리즘은 TPU에서 빠르고 CPU/GPU에서는 Philox에 비해 느립니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "c04JkebCPTPu"
      },
      "source": [
        "이 알고리즘들에 대한 상세한 정보는 ['Parallel Random Numbers: As Easy as 1, 2, 3'](https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) 논문을 참고해 주세요."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "random_numbers.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
